import os  
import re
import wsgiref.handlers
from jail import Handler
from jail.rest import Dispatcher
from jail.cache import Cache
from jail import sessions

import jail

from google.appengine.ext import webapp
#from google.appengine.ext import db

class DefaultHandler(Handler):
    target = r'/.*'
    def get(self):
        self.usererror('There is no default or index handler page defined')

class Rest(Dispatcher):
    models=None
    def initialize(self, request, response):     
        super(Rest,self).initialize(request, response)
        if jail.curSession and 'resthandlers' in jail.curSession and len(self.model_handlers)==0:
            self.add_models(jail.curSession['resthandlers'])
        
    def split_path(self):
        """Returns the request path split into non-empty components."""
        path = [i for i in self.request.path.split('/') if i]        
        if self.model_handlers:
            for handler in self.model_handlers.values():
                if handler.model_type.__module__ in path:
                    path.remove(handler.model_type.__module__)
        return path

class RequestProxy():
    def __init__(self,module_fullname,module, indexpath, debug=False):
        cache = Cache()
        self.rests=[]
        self.debug=debug
        self.moduleIndex={}
        if indexpath in cache:
            self.handlers=cache[indexpath]            
        else:
            self.prefix = '/'+module_fullname.replace('.','/')     
            self.handlers = [] 
            for attname in dir(module):
                classobj = getattr(module, attname)
                if type(classobj).__name__== 'type' and (module_fullname.startswith(classobj.__module__)):                    
                    self.addHandler(classobj)
                if type(classobj).__name__== 'PropertiedClass':
                    self.addRestHandler(classobj) 
                elif type(classobj).__name__=='module' and module_fullname==classobj.__name__:
                    for otherattname in dir(classobj):
                        otherclassobj = getattr(classobj, otherattname)
                        if type(otherclassobj).__name__=='type':
                            self.addHandler(otherclassobj)
            if len(self.rests)>0:
                #Rest.models = {}
                #if curses:
                if not jail.curSession:
                    jail.curSession = sessions.Session()
                resthandlers={}
                for rest in self.rests:
                    #Rest.models[rest['model'].__name__.lower()]=rest['model']
                    resthandlers[rest['model'].__name__.lower()]=rest['model']
                    self.handlers.append((rest['target'],Rest))
                if len(resthandlers)>0:
                    jail.curSession['resthandlers']=resthandlers
                else:
                    if ('resthandlers' in resthandlers):
                        jail.curSession.delete()
            
            if (self.moduleIndex.has_key(self.prefix)):
                self.handlers.append((self.prefix+'.*',self.moduleIndex[self.prefix]))
                cache[indexpath]=self.handlers
            else:
                self.handlers.append(('.*',DefaultHandler))

    # add a handler to the handler collection
    # it does not add default handler such as .*
    def addRestHandler(self,classobj):
        name = classobj.__name__
        if not name == 'Model':
            target = self.prefix+'/'+name.lower()+'/.*'
            self.rests.append({
                'target':target,
                'model':classobj
            })
                
    # add a handler to the handler collection
    # it does not add default handler such as .*
    def addHandler(self,classobj):
        if issubclass(classobj, Handler):
            name = classobj.__name__
            if not name == 'Handler':
                target = classobj.target
                if not target:
                    if (name.lower()=="index"):
                        self.moduleIndex[self.prefix]=classobj
                    else:
                        target = self.prefix+'/'+name.lower()
                        self.handlers.append((target,classobj))
                else:
                    if type(target).__name__=='str':
                        if (target=='.*'):
                            self.moduleIndex[self.prefix]=classobj
                        else:
                            self.handlers.append((self.prefix+'/'+target,classobj))
                    elif type(target).__name__=='list':
                        for item in target:
                            if item!='':
                                if (item=='.*') and (not self.prefix in self.moduleIndex): 
                                    self.moduleIndex[self.prefix]=classobj
                                else:
                                    self.handlers.append((self.prefix+'/'+item,classobj))
                    if (name.lower()=="index") and (not self.prefix in self.moduleIndex):
                        self.moduleIndex[self.prefix]=classobj

    def run(self):
        application = webapp.WSGIApplication(self.handlers, self.debug )
        wsgiref.handlers.CGIHandler().run(application)

def GetScriptModuleName(handler_path):
    """Determines the fully-qualified Python module name of a script on disk.
    
    Args:
      handler_path: CGI path stored in the application configuration (as a path
        like 'foo/bar/baz.py'). May contain $PYTHON_LIB references.
    
    Returns:
      String containing the corresponding module name (e.g., 'foo.bar.baz').
    """
    PYTHON_LIB_VAR = '$PYTHON_LIB'
    if handler_path.startswith(PYTHON_LIB_VAR + '/'):
        handler_path = handler_path[len(PYTHON_LIB_VAR):]
    handler_path = os.path.normpath(handler_path)
    
    extension_index = handler_path.rfind('.py')
    if extension_index != -1:
        handler_path = handler_path[:extension_index]
    module_fullname = handler_path.replace(os.sep, '.')
    module_fullname = module_fullname.strip('.')
    module_fullname = re.sub('\.+', '.', module_fullname)
    
    if module_fullname.endswith('.__init__'):
        module_fullname = module_fullname[:-len('.__init__')]
    
    return module_fullname

def importModuleWithName(module_fullname):
    if len(module_fullname)>0: 
        try:
            return module_fullname,__import__(module_fullname,globals())
        except ImportError:
            lastdotposition = module_fullname.rfind('.')
            if lastdotposition == -1:
                return None
            else:
                return importModuleWithName(module_fullname[:lastdotposition])
    else:
        return None
                    
def main():
    cgiresource = wsgiref.handlers.os.environ['PATH_INFO']
    module_fullname = GetScriptModuleName(cgiresource)
    indexpath = module_fullname 
    if len(module_fullname)>0:   
        module_fullname,module_object=importModuleWithName(module_fullname)
        if module_object:
            handlers = RequestProxy(module_fullname,module_object,indexpath,True)
            handlers.run()
            return
    application = webapp.WSGIApplication([(r'.*',DefaultHandler)], True )
    wsgiref.handlers.CGIHandler().run(application)

        
if __name__ == '__main__':
    main()